/***************************************************************
*  NAME:  
*	    sha1
*  SYNOPSIS:
*    	    
*  DESCRIPTION:
*     	    
*  HISTORY:
*      	         dietrich - Oct 7, 2011:  Created.
*
***************************************************************/
/*
 * Secure hash algorithm.
 *
 * Operates on 512 input, produces 160 bit output(20 byte).
 * The result is the sum modulo 2^32 of 5 integers
 *
 *  Break the 512 bit input in 16 4-bytes values
 *  Compute 80 4-bytes values W from the input
 * 
 * x is input array

 *  Rotations
 *  W[0<t<16] = x[t]
 *  W[17<t<80] = rotl-1 ( W[t-3] xor W[t-8] xor W[t-14] xor W[t-16])
 *              
 *
 *  SHA1 round:
 *     rotation
 *     add of another hash
 *     add of an indexed constant
 *     add of the W array
 *     add of a fonction dependant of the round number
 *     hashes are cycled.
 *     
 */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "digest.h"

static const int k[] = 
  {
    0x5a827999,    //  0 <= t <= 19
    0x6ed9eba1,    // 20 <= t <= 39
    0x8f1bbcdc,    // 40 <= t <= 59
    0xca62c1d6     // 60 <= t <= 79
  };


// ch function for rounds 0..19
static unsigned int ch(unsigned int x, unsigned int y, unsigned int z)
{
  return (x & y) ^ (~x & z);
}

// parity for rounds 20..39 and 60..79
static unsigned int parity(unsigned int x, unsigned int y, unsigned int z)
{
  return  x ^ y ^ z;
}

// maj function for rounds 40..59
static unsigned int maj (unsigned int x, unsigned int y, unsigned int z)
{
  return (x & y) ^ (x & z) ^ (y & z);
}


#define ROTL(x,c)  ((x<<(c))|(x>>(32-(c))))

// result is 5 32-bits ints.
#define SHA1_RESULT_SIZE 5

// block size 512 bits
#define SHA1_BLOCK_SIZE 64
#define SHA1_INPUT_BLOCK_SIZE (64-8)   // 8 bytes required for length padding

// Input block in 512 bits (64 bytes)
void sha1_block_operate(const unsigned char * block,
			unsigned int hash [SHA1_RESULT_SIZE])
{
  unsigned int W[80];
  unsigned int t;

  // 1. Prepare the W buffer

  // first 16 blocks of W are the original input blocks
  for (t=0;  t<16; t++)
    // Convert Big Endian to Little endian
    W[t]= (block[4*t]<<24)   // MSB
      | (block[4*t+1]<<16) 
      | (block[4*t+2]<<8) 
      | block[4*t+3];        // LSB
	

  for (t=16;  t<80; t++) {
    unsigned int w;
    w = W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16];
    W[t] = ROTL(w,1); // rotate left 1
  }



  unsigned int a,b,c,d,e;  

  a = hash[0];
  b = hash[1];
  c = hash[2];  
  d = hash[3];  
  e = hash[4];

  for (t=0; t<80; t++)
    {
      unsigned int T;
      T = ROTL(a,5) + e + k[(t/20)] + W[t];
      if (t <= 19) {
	T += ch(b,c,d);
      } else if (t<=39) {
	T += parity(b,c,d);
      } else if (t<=59) {
	T += maj(b,c,d);
      } else {
	T += parity(b,c,d);
      }
      e = d;
      d = c;
      c = ROTL(b,30);
      b = a;
      a = T;
    }

  hash[0] += a;
  hash[1] += b;
  hash[2] += c;
  hash[3] += d;
  hash[4] += e;
}


unsigned int sha1_initial_hash [] = {
  0x67452301,
  0xefcdab89,
  0x98badcfe,
  0x10325476,
  0xc3d2e1f0
};


void sha1_finalize(unsigned char * padded_block, int length_in_bits)
{
  // append the length for the last block in Big endian
  padded_block[SHA1_BLOCK_SIZE - 4] = (length_in_bits & 0xFF000000) >> 24;
  padded_block[SHA1_BLOCK_SIZE - 3] = (length_in_bits & 0x00FF0000) >> 16;
  padded_block[SHA1_BLOCK_SIZE - 2] = (length_in_bits & 0x0000FF00) >>  8;
  padded_block[SHA1_BLOCK_SIZE - 1] = (length_in_bits & 0x000000FF);  
}


void new_sha1_digest(digest_ctx * context)
{
	context->dtype = digest_SHA1;
	context->hash_len = 5;
	context->input_len = 0;
	context->block_len = 0;
	context->hash = (unsigned int *) malloc(context->hash_len * sizeof(unsigned int));
	memcpy(context->hash, sha1_initial_hash, context->hash_len * sizeof(unsigned int));
	memset(context->block, 0, DIGEST_BLOCK_SIZE);
	context->block_operate = sha1_block_operate;
	context->block_finalize = sha1_finalize;
	context->new_ctx = new_sha1_digest;	
}

